#include "backend.h"

Backend::Backend() {
    llvm::InitializeNativeTarget();
    llvm::InitializeAllTargetInfos();
    llvm::InitializeAllTargets();
    llvm::InitializeAllTargetMCs();
    llvm::InitializeAllAsmParsers();
    llvm::InitializeAllAsmPrinters();

    context = std::make_unique<llvm::LLVMContext>();
    mod = std::make_unique<llvm::Module>("calculator", *context);
    auto mainFunctionType = llvm::FunctionType::get(llvm::Type::getInt32Ty(*context), false);
    auto mainFunction = llvm::Function::Create(mainFunctionType, llvm::GlobalValue::ExternalLinkage, "main", mod.get());
    currentBlock = llvm::BasicBlock::Create(*context, "", mainFunction);
    builder = std::make_unique<llvm::IRBuilder<>>(currentBlock);

    auto targetTriple = llvm::sys::getDefaultTargetTriple();
    this->mod->setTargetTriple(targetTriple);
    std::string targetError;
    auto target = llvm::TargetRegistry::lookupTarget(targetTriple, targetError);
    auto cpu = "generic";
    auto features = "";
    llvm::TargetOptions options;
    auto relocationModel = llvm::Reloc::Model::PIC_;
    theTargetMachine = target->createTargetMachine(targetTriple, cpu, features, options, relocationModel);
    this->mod->setDataLayout(theTargetMachine->createDataLayout());
}

void Backend::emit(void) {
    this->builder->CreateRet(llvm::ConstantInt::get(llvm::Type::getInt32Ty(*this->context), 0));
    std::error_code errorCode;
    std::string filename = "main.s";
    llvm::raw_fd_ostream dest(filename, errorCode, llvm::sys::fs::OF_None);
    llvm::legacy::PassManager pass;
    llvm::CodeGenFileType type = llvm::CGFT_AssemblyFile; // llvm::CGFT_ObjectFile;
    this->theTargetMachine->addPassesToEmitFile(pass, dest, nullptr, type);
    pass.run(*(this->mod));
    dest.flush();
    this->mod->print(llvm::outs(), nullptr);
}
